﻿// TempFileManager
// 
// Manger for temporary scan files
// Implements a rolling file buffer and functionality
// for tracking saved changes.
// 
// FLMScan - Featured by FabLab Munich


// Basic ideas:
// 
// Tracking saved changes
// 
// - New scans are simply saved to new temp folder on disk
// - If user saves latest scan, the name of the saved folder is stored in a variable and on disk (FolderDescriptor)
// - On query for unsaved changes, the last saved scan is retrieved and compared against the latest saved scan on disk
// - On startup, the folder descriptor is read and the latest saved scan is retrieved

// Saved scan functionality:
// - On save, persist saved folder name in FolderDescriptor
// - On query, compare saved folder name against newest folder on disk
// - On startup, retrieve saved folder name from FolderDescriptor

using System;
using System.Text;
using System.Drawing;
using System.Collections.Generic;
using FLMScan.Tools;
using log4net;

namespace FLMScan
{
    class TempFileManager
    {
        private bool isDisposed = false;
        private ILog logger;

        private IFileSystem fileSystem;
        private String tempFolder;        
        private TempFolderContents tempFolderContents;
        private TempFolderDescriptor tempFolderDescriptor;


        private int nextTempFolderIndex = 0;
        private Dictionary<int,String> folderIdToFolderPath;
        private int lastSavedFolderIndex = 0;

        private const int NextDefaultIndex = 1;
        private const int MaxTempDirectoryCount = 5;

        private const string DefaultTempFolder = @"C:\Temp";
        private const string DefaultBitmapFilePrefix = "Image";
        private const string DefaultBitmapFileExtension = "tif";        
        private const string LogTempFileManagerInitialize = "Initializing TempFileManager";
        private const string LogInvalidTempFilePath = "Invalid temp file path, setting fallback path: ";
        private const string LogTempFileManagerLocation = "Temp file location: ";
        private const string LogTempFileManagerDirectoryCreated = "Created temp file directory: ";                

        public TempFileManager(IFileSystem fileSystem, String tempFolder)
        {
            logger = LogManager.GetLogger(typeof(TempFileManager));

            this.fileSystem = fileSystem;
            this.tempFolder = tempFolder;
            
            folderIdToFolderPath = new Dictionary<int, String>();
            tempFolderContents = new TempFolderContents(fileSystem, tempFolder);
            tempFolderDescriptor = new TempFolderDescriptor(fileSystem, tempFolder);
            nextTempFolderIndex = tempFolderContents.NextFolderIndex;

            Initialize();
        }

        public int StartNewTempFolder()
        {
            int currentTempFolderIndex = nextTempFolderIndex;
            ++nextTempFolderIndex;

            String folderIndex = tempFolderContents.NextFolderIndex.ToString();
            String tempFolderPath = System.IO.Path.Combine(tempFolder, folderIndex);            

            folderIdToFolderPath.Add(currentTempFolderIndex, tempFolderPath);

            fileSystem.CreateDirectory(tempFolderPath);
            logger.Debug(LogTempFileManagerDirectoryCreated + tempFolderPath);            

            return currentTempFolderIndex;
        }

        public void Serialize(Bitmap bitmap, int folderId, int index)
        {
            if (folderIdToFolderPath.ContainsKey(folderId))
            {
                String tempFolderPath = folderIdToFolderPath[folderId];
                String tempFilePath = tempFolderPath + "\\" + DefaultBitmapFilePrefix + index + "." + DefaultBitmapFileExtension;
                fileSystem.Serialize(bitmap, tempFilePath);                
            }
        }

        public void Serialize(ObjectData data)
        {

        }        

        public void EndTempFolder(int folderId)
        {
            if (folderIdToFolderPath.ContainsKey(folderId))
            {
                List<String> directories = fileSystem.GetDirectories(tempFolder);

                // if maximum number of saved scans is exceeded, delete oldest scan
                if (directories.Count > MaxTempDirectoryCount)
                {                    
                    String oldestDirectoryPath = System.IO.Path.Combine(tempFolder, tempFolderContents.SmallestFolderIndex.ToString());
                    fileSystem.Delete(oldestDirectoryPath);
                }                
            }
        }

        public void SaveAs(int folderId, String destinationPath)
        {
            lastSavedFolderIndex = folderId;

            // persist information that this folder was saved
            tempFolderDescriptor.Serialize(lastSavedFolderIndex);
            
            // copy folder contents to requested destination
            fileSystem.Copy(System.IO.Path.Combine(tempFolder, folderId.ToString()), destinationPath);
        }

        public bool LastScanUnsaved()
        {
            return (lastSavedFolderIndex < tempFolderContents.BiggestFolderIndex);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Initialize()
        {
            logger.Debug(LogTempFileManagerInitialize);            
                        
            // directory not existing yet
            if (!fileSystem.DirectoryExists(tempFolder))
            {
                if (fileSystem.CreateDirectory(tempFolder) == false)
                {
                    tempFolder = DefaultTempFolder;
                    logger.Warn(LogInvalidTempFilePath + tempFolder);
                }

                tempFolderDescriptor.Serialize(TempFolderDescriptor.UnknownSaveIndex);
            }
            else
            {
                if (fileSystem.FileExists(tempFolderDescriptor.FilePath))
                {
                    tempFolderDescriptor.Deserialize();
                    lastSavedFolderIndex = tempFolderDescriptor.SavedFolderIndex;
                }
                else
                {
                    tempFolderDescriptor.Serialize(TempFolderDescriptor.UnknownSaveIndex);
                }
            }

            logger.Debug(LogTempFileManagerLocation + tempFolder);
        }
        
        private void Dispose(bool isDisposing)
        {
            if (isDisposed)
                return;

            if (isDisposing)
            {
                isDisposed = true;                
            }
        }
    }    
}
